#include <iostream>
#include <functional>

int add(int a, int b) {
    return a + b;
}

int func(int a, int b, int c) {
    std::cout << b << std::endl;
    return a - c;
}

class BinderTest {
private:
    int a;
public:
    BinderTest(int _a) : a(_a) {}

public:
    void PrintA(int i) { 
        std::cout << "this: " << this <<
            ", a: " << a <<
            ", i: " << i << std::endl; 
    }
};

class Test {
public:
    Test() { std::cout << "Test()" << std::endl; }
    Test(const Test&) { std::cout << "Test(const Test&)" << std::endl; }
    Test(Test&&) { std::cout << "Test(Test&&)" << std::endl; }
};

void funcVal(Test) {}

void funcRef(Test&) {}

void funcMove(Test&&) {}

int main() {
    {
        auto add5 = 
            std::bind(add, 5, std::placeholders::_1);
        
        int result = add5(10);  //result = 15

        std::cout << "add5: " <<  result << std::endl;
    }

    {
        auto func1 = 
            std::bind(func, std::placeholders::_2, 10, std::placeholders::_1);

        int result = func1(10, 5);

        std::cout << "func1: " <<  result << std::endl;
    }


    {
        BinderTest bt(100);
        auto func = std::bind(&BinderTest::PrintA, &bt, std::placeholders::_1);

        std::cout << "bt: " << &bt << std::endl;
        func(200);
    }

    Test t;
    auto func_Val = std::bind(funcVal, std::move(t));
    auto func_Ref = std::bind(funcRef, std::ref(t));
    auto func_move = std::bind(funcMove, std::move(t));

    return 0;
}